/*
*    Phantom Test Driver v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ptd;

import javax.swing.tree.*;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.CellEditor;
import java.awt.Component;
import javax.swing.event.CellEditorListener;
import javax.swing.JLabel;
import java.awt.event.*;
import java.util.EventObject;

import java.awt.dnd.*;
import java.awt.datatransfer.Transferable;
import java.awt.Cursor;

import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.Icon;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Color;

import ssi_colorizer.*;

//import java.io.FileInputStream;
//import java.io.FileOutputStream;

import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.*;

import java.util.Vector;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.MenuElement;
import javax.swing.UIManager;



/**
 *
 * @author John
 */
public class PTDFunctions extends JTree implements DragGestureListener, DragSourceListener{

    public PTDMain pW;

    private DragSource dragSource;
    private boolean bStaticUI;

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public void setParent(PTDMain In){
        pW = In;
    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    
    public void Initialize(String Input){
        String[] z = Input.split("&");
        
        String[] s;
        if(z.length > 1){
           
        }else{
           s = Input.split("%");
        }
         
        String Vars = "";
        
        DefaultMutableTreeNode Root = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        for(int k = 0; k < z.length; k++)
        {       
            int istart = 0;
            s = z[k].split("%");
            if(k == 0){
                Vars = s[0];
                istart = 1;
            }
            
            for(int i = istart; i < s.length; i++){
                String[] q = s[i].split("#");
                PTDFunctionsInfo newInfo = new PTDFunctionsInfo();
                FunctionsBase aBase = new FunctionsBase();

                if(q.length > 0){
                    aBase.myName = q[0];
                    if(k == 0){
                        aBase.myType = aBase.TYPE_PACKAGE;
                    }else{
                        aBase.myType = aBase.TYPE_VARIABLE;
                    }
                    newInfo.init(aBase);
                    if(q.length > 1){ // Only add packages with functions
                        DefaultMutableTreeNode Node = new DefaultMutableTreeNode(newInfo, true);
                        Root.add(Node);
                        for(int j = 1; j < q.length; j++){
                            FunctionsBase FuncBase = new FunctionsBase();
                            PTDFunctionsInfo FuncInfo = new PTDFunctionsInfo();

                            String[] x = q[j].split(" ");
                            String Name;
                            if(x.length > 1){
                                Name = x[1] + " : " + x[0];
                            }else{
                                Name = q[j];
                            }

                            FuncBase.myName = Name;
                            if(k == 0){
                                FuncBase.myType = FuncBase.TYPE_FUNCTION;
                            }else{
                                FuncBase.myType = FuncBase.TYPE_MEMBER;
                            }
                            FuncInfo.init(FuncBase);
                            DefaultMutableTreeNode FuncNode = new DefaultMutableTreeNode(FuncInfo, true);
                            Node.add(FuncNode);
                        }
                    }
                }

            }
        }
        TreePath aPath = new TreePath(Root.getPath());
        this.expandPath(aPath);
        
        if(Vars.length() > 0){
            Vars = Vars.replaceAll(";", "|");
            SSI_ColorContext.DataTypePattern = Vars;
        }
    }
    
    /*
    public DefaultMutableTreeNode loadTreeNode(BufferedReader In, DefaultMutableTreeNode Top){
        DeclBase NewItem = new DeclBase();
        DefaultMutableTreeNode CurrNode = Top;
        int iLevel = 0;
        int LastLevel = 0;
        int Move = 0;
        
        while((iLevel = NewItem.load(In)) != 0){
            PTDFunctionsInfo newInfo = new PTDDeclInfo();
            newInfo.init(NewItem);
            DefaultMutableTreeNode Node = new DefaultMutableTreeNode(newInfo, true);
            if(iLevel == 1){
                Top.insert(Node, Top.getChildCount());
                CurrNode = Top;
                LastLevel = 1;
            }else{
                Move = iLevel - LastLevel;
                if(Move == 0){
                    CurrNode.insert(Node, CurrNode.getChildCount());
                }else if(Move < 0){
                    while(Move < 0){
                        CurrNode = (DefaultMutableTreeNode)CurrNode.getParent();
                        Move = Move + 1;
                        if(CurrNode == Top){  // Cant go above top...
                            iLevel = 1;
                            Move = 0;
                        }
                    }
                    CurrNode.insert(Node, CurrNode.getChildCount());
                }else if(Move == 1){
                    CurrNode = (DefaultMutableTreeNode)CurrNode.getChildAt(CurrNode.getChildCount()-1); // Get last child
                    if(CurrNode == null){
                        return null;
                    }
                    CurrNode.insert(Node, CurrNode.getChildCount());
                }else{
                    // Cant go more than one level deeper
                    return null;
                }
                LastLevel = iLevel;
                if(LastLevel <= 0){
                    LastLevel = 1;
                }
            }
            NewItem = new DeclBase();
        }
        
        return Top;
    } 
     * */   
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private DefaultMutableTreeNode getSelectedTreeNode(){
        TreePath SelPath = getSelectionPath();
        if(SelPath == null){
            return null;
        }
        DefaultMutableTreeNode SelNode = (DefaultMutableTreeNode)SelPath.getLastPathComponent();
        if(SelNode == null){
            return null;
        }
        return SelNode;
    }

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    private DefaultMutableTreeNode getSelectedDeclarations(){
        DefaultMutableTreeNode currRoot = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        DefaultMutableTreeNode SelNode = getSelectedTreeNode();
        if(SelNode == null){
            return null;
        }
        if(SelNode == currRoot){
            return null;
        }
        while(SelNode.getParent() != currRoot){
            SelNode = (DefaultMutableTreeNode)SelNode.getParent();
        }
        return SelNode;
    }
    
    
   public void dragDropEnd(DragSourceDropEvent dtde) {
       
   }
    
   public void dragExit(DragSourceEvent dtde) {
       
   }
   
   public void dragEnter(DragSourceDragEvent dtde) {
       
   }
   
   public void dragOver(DragSourceDragEvent dtde) {
       
   }
   
   public void dropActionChanged(DragSourceDragEvent dtde) {
       
   }
    
    public void dragGestureRecognized(DragGestureEvent e) {
        DefaultMutableTreeNode dragNode = getSelectedTreeNode();
        FunctionsBase transferBase = new FunctionsBase();
        transferBase.myName = "";
        
        DefaultMutableTreeNode currRoot = (DefaultMutableTreeNode)((DefaultTreeModel)treeModel).getRoot();
        
        if (dragNode != null) {
            if(dragNode == currRoot){
                transferBase.myName = "";
            }else if(dragNode.getParent() == currRoot){
                transferBase.myName = "";
            }else{
                PTDFunctionsInfo aDecl = (PTDFunctionsInfo) dragNode.getUserObject();
                
                String[] x = aDecl.myData.myName.split(":");
                String Name;
                if(x.length > 1){
                    Name = x[0];
                }else{
                    Name = aDecl.myData.myName;
                }
                
                Name = Name.trim();
                transferBase.myName = Name;
            }
            
            
            Cursor cursor = DragSource.DefaultCopyNoDrop;
            int action = e.getDragAction();
            if (action == DnDConstants.ACTION_MOVE){
                cursor = DragSource.DefaultMoveDrop;
            }
            dragSource.startDrag(e, cursor, transferBase, this);
        }
    }
    
    /** Creates a new instance of PTDDecls */
    public PTDFunctions() {
        bStaticUI = true;
        PTDFunctionsCell CellEdit = new PTDFunctionsCell();
        PTDFunctionsRender CellRender = new PTDFunctionsRender();
        
        addMouseListener(new PTDFunctionsMouseListener());
        
        this.showsRootHandles = true;
        setSelectionPath(null);
        ((DefaultTreeModel)treeModel).setRoot(null);
        
        setEditable(true);
        this.setEnabled(true);
        this.setVisible(true);
 
        setCellRenderer(CellRender);
        setCellEditor(CellEdit);
        
        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
        
        // Following is from java top 97 code...-----------
        dragSource = DragSource.getDefaultDragSource() ;
    
        DragGestureRecognizer dgr = dragSource.createDefaultDragGestureRecognizer(
            this,                             //DragSource
            DnDConstants.ACTION_COPY_OR_MOVE, //specifies valid actions
            this                              //DragGestureListener
        );

        /* Eliminates right mouse clicks as valid actions - useful especially
        * if you implement a JPopupMenu for the JTree
        */
        //dgr.setSourceActions(dgr.getSourceActions() & ~InputEvent.BUTTON3_MASK);
        // --------------------------------------------------

        initTree();
        
    }
    
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////    
    public void initTree(){
        FunctionsBase aBase = new FunctionsBase();
        PTDFunctionsInfo anInfo = new PTDFunctionsInfo();
        aBase.myName = "Functions";
        aBase.myType = aBase.TYPE_PACKAGE;
        anInfo.init(aBase);
        DefaultMutableTreeNode Root = new DefaultMutableTreeNode(anInfo, true);
        if(Root != null){
            setSelectionPath(null);
            ((DefaultTreeModel)treeModel).setRoot(Root);
        }        
    }
    
   public void updateUI() {
       if(bStaticUI == false){
           setUI(UIManager.getUI(this));
       }
       // Dont want this UI to change
   }

    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDDeclInfo ///////////////////////////////////////
    public class PTDFunctionsInfo extends Object{
        public FunctionsBase myData;
        public PTDFunctionsFrame myFrame;
        
        // -----------------------------------------------------
        public PTDFunctionsInfo(){
            myData = null;
            myFrame = null;
        }
        
        // -----------------------------------------------------
        public void init(FunctionsBase newData){
            myData = newData.duplicate();
            myFrame = new PTDFunctionsFrame(myData);
        }
        
    }
    // END PTDNodeInfo ///////////////////////////////////////
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDDECLSCELL ///////////////////////////////////////
    // Used for when the cell is editable
    public class PTDFunctionsCell implements TreeCellEditor{
        
        // -----------------------------------------------------
        public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row){
            DefaultMutableTreeNode node =  (DefaultMutableTreeNode)value;

            if(node.isLeaf() || node.getAllowsChildren())
            {
                PTDFunctionsInfo anInfo = (PTDFunctionsInfo)node.getUserObject();                
                anInfo.myFrame.setSelectState(true);
                anInfo.myFrame.update(anInfo.myData);
                return anInfo.myFrame;
            }
            else
            {
                return new JLabel("Error");
            }
        }
        
        // -----------------------------------------------------
        public void addCellEditorListener(CellEditorListener l){
            
        }

        // -----------------------------------------------------
        public void removeCellEditorListener(CellEditorListener l){
            
        }
        
        // -----------------------------------------------------
        public Object getCellEditorValue(){
            return this;
        }
        
        // -----------------------------------------------------
        public void cancelCellEditing(){
        }
 
        // -----------------------------------------------------
        public boolean stopCellEditing(){
            return true;
        }
 
        // -----------------------------------------------------
        public boolean isCellEditable(EventObject isEditableEvt){
            if (isEditableEvt instanceof MouseEvent){
                MouseEvent me = (MouseEvent) isEditableEvt;
                if (me.getClickCount() == 1){
                    return true;
                }
            }
            return false;
        }
        
        // -----------------------------------------------------
        public boolean shouldSelectCell(EventObject selectCell){
            return true;
        }
    }
    // END PTDTreeCell ///////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDDeclsRender ///////////////////////////////////////
    // Used to render the tree item under non-edit circumstances
    public class PTDFunctionsRender extends DefaultTreeCellRenderer{
        
        // -----------------------------------------------------
        public PTDFunctionsRender(){

        }
 
        // -----------------------------------------------------
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus){
            DefaultMutableTreeNode node =  (DefaultMutableTreeNode)value;            
            PTDFunctionsInfo anInfo = (PTDFunctionsInfo)node.getUserObject();
            if(anInfo == null){
              return new JLabel("Error");  
            }
            if(selected){
                anInfo.myFrame.setSelectState(true);
            }else{
                anInfo.myFrame.setSelectState(false);
            }
            anInfo.myFrame.update(anInfo.myData);
            return anInfo.myFrame;

        }
        
    }
    // END PTDTreeRender ///////////////////////////////////////

        ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // PTDTreeFrame ///////////////////////////////////////
    public class PTDFunctionsFrame extends JPanel{
        public JLabel myLabel;
        public Icon myIcon;
        
        // -----------------------------------------------------
        public PTDFunctionsFrame(FunctionsBase InData){
            
            myLabel = new JLabel(InData.myName);
            if(InData.myType == InData.TYPE_PACKAGE){
                myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_FUNCTIONSET_ICON);
                myLabel.setToolTipText("Package Functions - Click and drag to script");
            }else if(InData.myType == InData.TYPE_FUNCTION){
                myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_FUNCTION_ICON);
                // This does not allow dragging if item is selected...
                //myLabel.setToolTipText("Function - Click and drag to script");
            }else if(InData.myType == InData.TYPE_VARIABLE){
                myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_VARIABLE_ICON);
                myLabel.setToolTipText("Variable Member Functions - Click and drag to script");
            }else{
                myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_MEMBER_ICON);
                // This does not allow dragging if item is selected...
                //myLabel.setToolTipText("Member Function - Click and drag to script");
            }
            
            //}else if(InData.myType == FunctionsBase.TYPE_WIN){
            //    myIcon = PTDImageLoader.getImageIcon(PTDImageLoader.IMG_DECL_ICON);
            //}
            myLabel.setIcon(myIcon);
            
            setLayout(new java.awt.GridBagLayout());

            if(InData.myType == InData.TYPE_FUNCTION || InData.myType == InData.TYPE_MEMBER){
                myLabel.setFont(new java.awt.Font("Arial", 0, 12));
            }else{
                myLabel.setFont(new java.awt.Font("Arial", java.awt.Font.BOLD, 12));
                
            }
            
            myLabel.setBackground(Color.WHITE);
            this.setBackground(Color.WHITE);
            add(myLabel);
            
        }

        
        // -----------------------------------------------------
        public void setSelectState(boolean selState){
            if(selState){
                Color LtBlue = new Color(200, 220, 255);
                myLabel.setBackground(LtBlue);
                this.setBackground(LtBlue);
            }else{
                myLabel.setBackground(Color.WHITE);
                this.setBackground(Color.WHITE);
            }
        }
        
        public void update(FunctionsBase Info){
            myLabel.setText(Info.myName);
        }
        
        
    }
    // END PTDTreeFrame ///////////////////////////////////////
    
    public class FunctionsBase extends Object implements Transferable{

        public String myName;
        public int myType;
        public int TYPE_PACKAGE = 1;
        public int TYPE_FUNCTION = 2;
        public int TYPE_VARIABLE = 3;
        public int TYPE_MEMBER = 4;



        /** Creates a new instance of DeclBase */
        public FunctionsBase() {
             myType = TYPE_FUNCTION;
             myName = "";
        }

        public Object getTransferData(DataFlavor df) throws UnsupportedFlavorException, IOException {
            if (df.equals( DataFlavor.getTextPlainUnicodeFlavor() ) == false){
                throw new UnsupportedFlavorException(df);
            }
            return myName;
        }
        public DataFlavor[] getTransferDataFlavors() {
           DataFlavor Flavors[] = {DataFlavor.getTextPlainUnicodeFlavor()};
           return Flavors;
        }

        //Returns whether or not the specified data flavor is supported for this object.
        public boolean isDataFlavorSupported(DataFlavor flavor) {
           if (flavor == DataFlavor.getTextPlainUnicodeFlavor()){
               return true;
           }
          return false;
        }

        public FunctionsBase duplicate(){
            FunctionsBase Ret = new FunctionsBase();
            Ret.myName = myName;
            Ret.myType = myType;
            return Ret;
        }

        public boolean isEqual(FunctionsBase In){
            if(myName.compareTo(In.myName) != 0){
                return false;
            }
            if(myType != In.myType){
                return false;
            }
            return true;
        }

    }
    
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    public class PTDFunctionsMouseListener extends MouseAdapter{
        // -----------------------------------------------------
        public void mousePressed(MouseEvent e) {
            // Required to allow keyboard navigation when a tree item is selected.
            requestFocus();
        }
    }
    
    
}
